package com.knowledge.plus.创建定时任务.Scheduled注解;

import com.knowledge.plus.创建线程and线程池.注解创建线程.config.ThreadPoolTaskConfig;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 要使用 @Scheduled 注解，
 * 首先需要在启动类添加 @EnableScheduling 启用Spring的计划任务执行功能，这样可以在容器中的任何Spring管理的bean上检测 @Scheduled 注解，执行计划任务
 * -
 * 注解 @Scheduled：默认是单线程执行的，多个 @Scheduled 任务都用的同一个线程。
 *                 如果某个任务是个耗时的操作，那么其它定时任务都会等待该任务的执行完成，从而造成堵塞。
 *                 Spring3.0以后自带，可以将它看成一个轻量级的Quartz，使用起来比Quartz简单许多。
 * -
 * 注解 @Async：异步执行方法
 *
 * @author PF.Tian
 * @since 2021/09/13
 */
@Component
public class ScheduleTask {

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 固定间隔，任务固定间隔时间，时间自前一次完成后计算
     */
    @Scheduled(fixedDelay = 20000)
    public void fixedDelaySchedule() {
        System.out.println("上一次执行完毕时间点之后20秒再执行" + "  " + sdf.format(new Date()));
    }

    /**
     * 不加 @Async 任务阻塞，20000ms 执行一次
     * 加上 @Async 任务不会阻塞
     * <p>
     * 固定频率，任务固定间隔时间，时间自前一次开始后计算
     */
    @Async
    @Scheduled(fixedRate = 10000)
    public void testScheduleTask() {
        try {
            Thread.sleep(20000);
            System.out.println("Spring自带的线程池1 " + Thread.currentThread().getName() + "  " + sdf.format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * corn表达式，当方法的执行时间超过任务调度频率时，调度器会在下个周期执行
     */
    @Async
    @Scheduled(cron = "*/30 * * * * ?")
    public void testAsync() {
        try {
            Thread.sleep(1000);
            System.out.println("Spring自带的线程池2 " + Thread.currentThread().getName() + "  " + sdf.format(new Date()));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 指定异步使用自定义线程池{@link ThreadPoolTaskConfig}
     * 加上 @PostConstruct 服务启动就可以立即执行一次，再按照 cron表达式等待下一次执行
     * 不加则启动服务时不会执行
     */
    @Async("scheduledExecutorService")
    @Scheduled(cron = "*/30 * * * * ?")
    @PostConstruct
    public void executor() {
        System.out.println("执行线程池 " + Thread.currentThread().getName() + "  " + sdf.format(new Date()));
    }


}
